{#let metrics=info:buildMetrics.get}

{#include main fluid=true}
{#style}
#chartjs-tooltip {
  color: white;
  border-radius: 0em 1em 1em 1em;
  padding: 1em;
}
.tooltip-steps {
  padding-left: 0.5em;
  margin-bottom: 0;
  font-size: 1.2em;
}
.tooltip-title {
  font-size: 1.5em;
  font-weight: bold;
}
{/style}
{#title}Build Steps{/title}
{#body}
<p class="lead mt-4 mb-4">
Executed <strong>{metrics.records.size}</strong> build steps on <strong>{metrics.threadSlotRecords.keys.size}</strong> threads in {metrics.duration} ms.
</p>

<p>
<a href="#build-steps-chart" class="btn btn-secondary" role="button">Build Steps Concurrent Execution Chart</a>
</p>

<table class="table table-striped mb-4">
   <thead class="thead-dark">
    <tr>
      <th scope="col">#</th>
      <th scope="col">Build Step</th>
      <th scope="col">Started</th>
      <th scope="col">Duration</th>
      <th scope="col">Thread</th>
      <th scope="col">Actions</th>
    </tr>
   </thead>
   <tbody>
    {#for record in metrics.records}
    <tr>
      <td>{record_count}</td>
      <td>
      {record.stepId}
      </td>
      <td>
      {record.started} 
      </td>
      <td>
      {record.duration} ms 
      </td>
      <td>
      {record.thread}
      </td>
      <td>
        {#if !metrics.dependencyGraphs.get(record.stepId).links.empty}
        <a class="btn btn-primary btn-sm" href="build-step-dependency-graph?stepId={record.encodedStepId}" role="button" title="Show dependency graph"><i class="fa-solid fa-diagram-project"></i></a>
        {/if}
      </td>
    {/for}
   </tbody>
  </table>
  
  <h2 id="build-steps-chart" class="mt-4">Build Steps Concurrent Execution Chart</h2>
  <div id="buildStepsChartContainer" style="width: 100%;">
    <canvas id="buildStepsChart"></canvas>
  </div>

{#script}
  const labels = [ {#each metrics.slots}{it}{#if it_hasNext},{/if}{/each} ];
  const nextColor = function(number) {
    const hue = number * 137.508; // golden angle approximation
    return "hsl(" + hue +",80%,65%)";
  };
  
  const threadBuildSteps = {
    {#for entry in metrics.threadSlotRecords.entrySet}
       "{entry.key}" : [
         {#for data in entry.value}
         [ {#for stepId in data} '{stepId}',{/for} ],
         {/for}
       ],
    {/for}
  }
  
  const data = {
     labels: labels,
     datasets: [ 
     {#for entry in metrics.threadSlotRecords.entrySet}
     {
      label: '{entry.key}',
      data: [{#each entry.value}{#if it.empty}0{#else}1{/if},{/each}],
      backgroundColor: nextColor({entry_index}),
     },
     {/for}
     ]
  };
  
  const externalTooltip = (context) => {
    const { chart, tooltip } = context;
    let tooltipEl = document.getElementById('chartjs-tooltip');
    
    // Create element on first render
    if (!tooltipEl) {
      tooltipEl = document.createElement('div');
      tooltipEl.id = 'chartjs-tooltip';
      chart.canvas.parentNode.appendChild(tooltipEl);
    }

    // Hide if no tooltip
    if (tooltip.opacity === 0) {
      tooltipEl.style.opacity = 0;
      return;
    }
    
    // Set caret Position
    tooltipEl.classList.remove('above', 'below', 'no-transform');
    if (tooltip.yAlign) {
      tooltipEl.classList.add(tooltip.yAlign);
    } else {
      tooltipEl.classList.add('no-transform');
    }

    let innerHtml = '';
    // We expect a single tooltip item
    const tooltipItem = context.tooltip.dataPoints[0];
    const thread = tooltipItem.dataset.label;
    const buildStepIds = threadBuildSteps[thread][tooltipItem.dataIndex];
    
    innerHtml += '<div class="tooltip-title">' + thread + '</div>';
    innerHtml += '<ul class="tooltip-steps">';
    buildStepIds.forEach(function(stepId, i) {
      innerHtml += '<li title="';
      innerHtml += stepId;
      innerHtml += '">';
      const lastDot = stepId.lastIndexOf('.');
      if (lastDot > 0) {
        innerHtml += stepId.substring(lastDot + 1);
      } else {
        innerHtml += stepId;
      }
      innerHtml += '</li>';
    });
    innerHtml += '</ul>';
    
    let ulRoot = tooltipEl;
    ulRoot.innerHTML = innerHtml;
    
    const position = context.chart.canvas.getBoundingClientRect();
    const bodyFont = Chart.helpers.toFont(tooltip.options.bodyFont);

    // Display, position, and font
    tooltipEl.style.opacity = 1;
    tooltipEl.style.position = 'absolute';
    
    const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;
    tooltipEl.style.left = positionX + tooltip.caretX + 'px';
    tooltipEl.style.top = (positionY + tooltip.caretY + 7) + 'px';
    
    //tooltipEl.style.left = position.left + window.pageXOffset + tooltip.caretX + 'px';
    //tooltipEl.style.top = position.top + window.pageYOffset + tooltip.caretY + 'px';
    tooltipEl.style.font = bodyFont.string;
    tooltipEl.style.padding = tooltip.padding + 'px ' + tooltip.padding + 'px';
    tooltipEl.style.background = 'rgba(0, 0, 0, 0.7)';
    tooltipEl.style.pointerEvents = 'none';
  };
  
  const config = {
    type: 'bar',
    data: data,
    options: {
        plugins: {
            title: {
                display: true,
                text: 'Build Step Concurrent Execution',
            },
            tooltip: {
                enabled: false,
                external: externalTooltip,
            }
        },
        responsive: true,
        scales: {
          x: {
            stacked: true,
            title: {
                display: true,
                text: "{metrics.slots.size} time slots ({metrics.slots.get(0)} ms)", 
            },
          },
          y: {
            stacked: true,
            title: {
                display: true,
                text: "Number of build threads used in a time slot", 
            }, 
          }
        }
    }
  };

  const ctx = document.getElementById('buildStepsChart').getContext('2d');
  const buildStepsChart = new Chart(ctx, config);

{#scriptref}
  <script src="{devRootAppend}/resources/js/chart.min.js"></script>
{/include}

{/let}